using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MapTestFramework.Common.Tests
{
    [TestClass]
    public class MapTestCaseCollectionFixture
    {
        #region Constructor And Initializing Members

        public MapTestCaseCollectionFixture()
        {
            return;
        }

        #endregion

        #region Additional test attributes

        // [ClassInitialize()]
        // public static void ClassInitialize(TestContext testContext) { }
        // [ClassCleanup()]
        // public static void ClassCleanup() { }
        // [TestInitialize()]
        // public void TestInitialize() { }
        // [TestCleanup()]
        // public void TestCleanup() { }

        #endregion

        #region Test Members

        #region Constructor Tests

        [TestMethod]
        public void ConstructSourceXPathSingle()
        {
            string[] sourceXPaths = new string[] { "Dummy1" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0]
                );

            AssertConstruction(collection, sourceXPaths);
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructSourceXPathSingleEmpty()
        {
            try
            {
                MapTestCases collection = new MapTestCases("");
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("sourceXPath", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: sourceXPath",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructSourceXPathSingleNull()
        {
            try
            {
                MapTestCases collection = new MapTestCases(null);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("sourceXPath", ex.ParamName, "Invalid parameter name.");
                Assert.AreEqual(
                    "Value cannot be null or empty.\r\nParameter name: sourceXPath",
                    ex.Message, "Invalid exception message."
                    );
                throw;
            }
            return;
        }
        [TestMethod]
        public void ConstructSourceXPathSingleExpectedXPathSingle()
        {
            string[] sourceXPaths = new string[] { "Dummy1" };
            string[] expectedXPaths = new string[] { "Dummy2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            AssertConstruction(collection, sourceXPaths, expectedXPaths);
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructSourceXPathsNull()
        {
            try
            {
                string[] sourceXPaths = null;
                string[] expectedXPaths = new string[] { "Dummy4" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("sourceXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value cannot be null.\r\nParameter name: sourceXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructSourceXPathsMultipleElementNull()
        {
            try
            {
                string[] sourceXPaths = new string[] { "Dummy1", null, "Dummy3" };
                string[] expectedXPaths = new string[] { "Dummy4" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("sourceXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("One of the xpath expressions is null or empty.\r\nParameter name: sourceXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructSourceXPathsMultipleElementEmpty()
        {
            try
            {
                string[] sourceXPaths = new string[] { "Dummy1", string.Empty, "Dummy3" };
                string[] expectedXPaths = new string[] { "Dummy4" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("sourceXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("One of the xpath expressions is null or empty.\r\nParameter name: sourceXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }
        [TestMethod]
        public void ConstructSourceXPathsMultipleExpectedXPathsMultiple()
        {
            string[] sourceXPaths = new string[] { "Dummy1", "Dummy2", "Dummy3" };
            string[] expectedXPaths = new string[] { "Dummy4", "Dummy5" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths, expectedXPaths
                );

            AssertConstruction(collection, sourceXPaths, expectedXPaths);
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructExpectedXPathsNull()
        {
            try
            {
                string[] sourceXPaths = new string[] { "Dummy1", "Dummy2", "Dummy3" };
                string[] expectedXPaths = null;
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentNullException ex)
            {
                Assert.AreEqual("expectedXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value cannot be null.\r\nParameter name: expectedXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructExpectedXPathsMultipleElementNull()
        {
            try
            {
                string[] sourceXPaths = new string[] { "Dummy1" };
                string[] expectedXPaths = new string[] { "Dummy2", null, "Dummy4" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("expectedXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("One of the xpath expressions is null or empty.\r\nParameter name: expectedXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ConstructExpectedXPathsMultipleElementEmpty()
        {
            try
            {
                string[] sourceXPaths = new string[] { "Dummy1" };
                string[] expectedXPaths = new string[] { "Dummy2", string.Empty, "Dummy4" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("expectedXPaths", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("One of the xpath expressions is null or empty.\r\nParameter name: expectedXPaths", ex.Message, "Invalid error message");
                throw;
            }
            return;
        }

        #endregion

        #region AddTestCase Tests

        [TestMethod]
        public void AddTestCaseSingleXPathSingle()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[] sourceValues = new string[] { "Value1" };
            string[] expectedValues = new string[] { "Value2" };
            collection.AddTestCase(sourceValues, expectedValues);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseSingleXPathMultiple()
        {
            string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
            string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths, expectedXPaths
                );

            string[] sourceValues = new string[] { "Value1", "Value2", "Value3" };
            string[] expectedValues = new string[] { "Value4", "Value5", "Value6" };
            collection.AddTestCase(sourceValues, expectedValues);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseSingleXPathSingleValueNull()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths, expectedXPaths
                );

            string[] sourceValues = null;
            string[] expectedValues = null;
            collection.AddTestCase(sourceValues, expectedValues);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseSingleXPathMultipleValueNull()
        {
            string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
            string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths, expectedXPaths
                );

            string[] sourceValues = null;
            string[] expectedValues = null;
            collection.AddTestCase(sourceValues, expectedValues);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseMultipleXPathSingle()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[][] sourceValues = new string[2][] { 
                new string[] { "Value1" }, new string[] { "Value2" } 
                };
            string[][] expectedValues = new string[2][] { 
                new string[] { "Value3" }, new string[] { "Value4"} 
                };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseMultipleXPathSingleValueNull()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[][] sourceValues = new string[2][] { null, null };
            string[][] expectedValues = new string[2][] { null, null };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        public void AddTestCaseMultipleXPathMultiple()
        {
            string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
            string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths, expectedXPaths
                );

            string[][] sourceValues = new string[2][] { 
                new string[] { "Value1", "Value2", "Value3" }, 
                new string[] { "Value4", "Value5", "Value6" }
                };
            string[][] expectedValues = new string[2][] { 
                new string[] { "Value7", "Value8", "Value9" }, 
                new string[] { "Value10", "Value11", "Value12" }
                };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            AssertValues(collection.SourceTestCaseValues, sourceValues, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues);
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddTestCaseMultipleXPathMultipleInvalidValueCountSource()
        {
            try
            {
                string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
                string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );

                string[][] sourceValues = new string[2][] { 
                    new string[] { "Value1", "Value2", "Value3" }, 
                    new string[] { "Value4", "Value6" }
                    };
                string[][] expectedValues = new string[2][] { 
                    new string[] { "Value7", "Value8", "Value9" }, 
                    new string[] { "Value10", "Value11", "Value12" }
                    };
                for (int i = 0; i < sourceValues.Length; i++)
                    collection.AddTestCase(sourceValues[i], expectedValues[i]);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("sourceValues", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value count does not match xpath count.\r\nParameter name: sourceValues", ex.Message, "Invalid error message");
                throw ex;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddTestCaseMultipleXPathMultipleInvalidValueCountExpected()
        {
            try
            {
                string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
                string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );

                string[][] sourceValues = new string[2][] { 
                    new string[] { "Value1", "Value2", "Value3" }, 
                    new string[] { "Value4", "Value5", "Value6" }
                    };
                string[][] expectedValues = new string[2][] { 
                    new string[] { "Value7", "Value8", "Value9" }, 
                    new string[] { "Value10", "Value12" }
                    };
                for (int i = 0; i < sourceValues.Length; i++)
                    collection.AddTestCase(sourceValues[i], expectedValues[i]);
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("expectedValues", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value count does not match xpath count.\r\nParameter name: expectedValues", ex.Message, "Invalid error message");
                throw ex;
            }
            return;
        }
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void AddTestCaseDirectlyInvalidValueCountSource()
        {
            try
            {
                string[] sourceXPaths = new string[] { "XPath1", "XPath2", "XPath3" };
                string[] expectedXPaths = new string[] { "XPath4", "XPath5", "XPath6" };
                MapTestCases collection = new MapTestCases(
                    sourceXPaths, expectedXPaths
                    );

                string[][] sourceValues = new string[2][] { 
                    new string[] { "Value1", "Value2", "Value3" }, 
                    new string[] { "Value4", "Value6" }
                    };
                string[][] expectedValues = new string[2][] { 
                    new string[] { "Value7", "Value8", "Value9" }, 
                    new string[] { "Value10", "Value11", "Value12" }
                    };
                for (int i = 0; i < sourceValues.Length; i++)
                    collection.SourceTestCaseValues.Add(new string[2] );
            }
            catch (ArgumentException ex)
            {
                Assert.AreEqual("item", ex.ParamName, "Invalid parameter name");
                Assert.AreEqual("Value count does not match xpath count.\r\nParameter name: item", ex.Message, "Invalid error message");
                throw ex;
            }
            return;
        }

        #endregion

        #region RemoveTestCase Tests

        [TestMethod]
        public void RemoveTestCase()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[][] sourceValues = new string[3][] { 
                new string[] { "Value1" }, new string[] { "Value2" }, 
                new string[] { "Value3" }
                };
            string[][] expectedValues = new string[3][] { 
                new string[] { "Value4" }, new string[] { "Value5"}, 
                new string[] { "Value6"}
                };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            collection.RemoveTestCase(1);

            string[][] sourceValues2 = new string[2][] {
                sourceValues[0], sourceValues[2]
                };
            string[][] expectedValues2 = new string[2][] {
                expectedValues[0], expectedValues[2]
                };

            AssertValues(collection.SourceTestCaseValues, sourceValues2, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues2);
            return;
        }
        [TestMethod]
        public void RemoveTestCaseFirst()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[][] sourceValues = new string[3][] { 
                new string[] { "Value1" }, new string[] { "Value2" }, 
                new string[] { "Value3" }
                };
            string[][] expectedValues = new string[3][] { 
                new string[] { "Value4" }, new string[] { "Value5"}, 
                new string[] { "Value6"}
                };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            collection.RemoveTestCase(0);

            string[][] sourceValues2 = new string[2][] {
                sourceValues[1], sourceValues[2]
                };
            string[][] expectedValues2 = new string[2][] {
                expectedValues[1], expectedValues[2]
                };

            AssertValues(collection.SourceTestCaseValues, sourceValues2, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues2);
            return;
        }
        [TestMethod]
        public void RemoveTestCaseLast()
        {
            string[] sourceXPaths = new string[] { "XPath1" };
            string[] expectedXPaths = new string[] { "XPath2" };
            MapTestCases collection = new MapTestCases(
                sourceXPaths[0], expectedXPaths[0]
                );

            string[][] sourceValues = new string[3][] { 
                new string[] { "Value1" }, new string[] { "Value2" }, 
                new string[] { "Value3" }
                };
            string[][] expectedValues = new string[3][] { 
                new string[] { "Value4" }, new string[] { "Value5"}, 
                new string[] { "Value6"}
                };
            for (int i = 0; i < sourceValues.Length; i++)
                collection.AddTestCase(sourceValues[i], expectedValues[i]);

            collection.RemoveTestCase(2);

            string[][] sourceValues2 = new string[2][] {
                sourceValues[0], sourceValues[1]
                };
            string[][] expectedValues2 = new string[2][] {
                expectedValues[0], expectedValues[1]
                };

            AssertValues(collection.SourceTestCaseValues, sourceValues2, false);
            AssertValues(collection.ExpectedTestCaseValues, expectedValues2);
            return;
        }

        #endregion

        #endregion

        #region Helper Members

        private static void AssertXPaths(TestCaseValueCollection collection, string[] xpaths)
        {
            AssertXPaths(collection, xpaths, true);
        }
        private static void AssertXPaths(TestCaseValueCollection collection, string[] xpaths, bool expected)
        {
            string name = expected ? "Expected" : "Source";
            Assert.IsNotNull(collection, "{0}XPathAndValues not created.", name);
            Assert.AreEqual(xpaths.Length, collection.GetXPaths().Length,
                "Invalid XPathCount for {0}XPathAndValues.", name
                );
            for (int i = 0; i < xpaths.Length; i++)
                Assert.AreEqual(xpaths[i], collection.GetXPaths()[i],
                    "Invalid {0} XPath value", name
                    );
        }
        private static void AssertValues(TestCaseValueCollection collection, string[] values)
        {
            AssertValues(collection, values, true);
            return;
        }
        private static void AssertValues(TestCaseValueCollection collection, string[] values, bool expected)
        {
            string name = expected ? "Expected" : "Source";

            Assert.AreEqual(1, collection.Count,
                "Invalid {0} TestCaseCount", name
                );
            for (int i = 0; i < collection.Count; i++)
                for (int j = 0; j < collection[i].Length; j++)
                    if (values == null)
                        Assert.AreEqual(
                            null, collection[i][j],
                            "Invalid {0} TestCase value", name
                            );
                    else
                        Assert.AreEqual(
                            values[j], collection[i][j],
                            "Invalid {0} TestCase value", name
                            );
            return;
        }
        private static void AssertValues(TestCaseValueCollection collection, string[][] values)
        {
            AssertValues(collection, values, true);
            return;
        }
        private static void AssertValues(TestCaseValueCollection collection, string[][] values, bool expected)
        {
            string name = expected ? "Expected" : "Source";

            Assert.AreEqual(values.Length, collection.Count,
                "Invalid {0} TestCaseCount", name
                );
            for (int i = 0; i < collection.Count; i++)
                for (int j = 0; j < collection[i].Length; j++)
                    if (values[i] == null)
                        Assert.AreEqual(
                            null, collection[i][j],
                            "Invalid {0} TestCase value", name
                            );
                    else
                        Assert.AreEqual(
                            values[i][j], collection[i][j],
                            "Invalid {0} TestCase value", name
                            );
            return;
        }

        private void AssertConstruction(MapTestCases collection, string[] sourceXPaths)
        {
            AssertConstruction(collection, sourceXPaths, null);
            return;
        }
        private void AssertConstruction(MapTestCases collection, string[] sourceXPaths, string[] expectedXPaths)
        {
            if (expectedXPaths == null)
                Assert.IsNull(collection.ExpectedTestCaseValues,
                    "ExpectedXPathAndValues was created."
                    );
            else
                AssertXPaths(
                    collection.ExpectedTestCaseValues, expectedXPaths
                    );
            AssertXPaths(
                collection.SourceTestCaseValues, sourceXPaths, false
                );
            return;
        }

        #endregion
    }
}
